{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1331faa1",
   "metadata": {},
   "source": [
    "可以在[Bookshop.org](https://bookshop.org/a/98697/9781098155438) 和\n",
    "[Amazon](https://www.amazon.com/_/dp/1098155432?smid=ATVPDKIKX0DER&_encoding=UTF8&tag=oreilly20-20&_encoding=UTF8&tag=greenteapre01-20&linkCode=ur2&linkId=e2a529f94920295d27ec8a06e757dc7c&camp=1789&creative=9325)获取纸制版和电子版的*Think Python 3e*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "103cbe3c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from os.path import basename, exists\n",
    "\n",
    "def download(url):\n",
    "    filename = basename(url)\n",
    "    if not exists(filename):\n",
    "        from urllib.request import urlretrieve\n",
    "\n",
    "        local, _ = urlretrieve(url, filename)\n",
    "        print(\"Downloaded \" + str(local))\n",
    "    return filename\n",
    "\n",
    "download('https://gitee.com/regentsai/Think_Python_3e_CN/blob/master/thinkpython.py');\n",
    "download('https://gitee.com/regentsai/Think_Python_3e_CN/blob/master/diagram.py');\n",
    "\n",
    "import thinkpython"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bd858a8",
   "metadata": {},
   "source": [
    "# 第3章：函数\n",
    "\n",
    "在上一章，我们使用了几个Python提供的函数，例如`int`和`float`；以及`math`模块提供的几个函数，例如`sqrt`和`pow`。\n",
    "\n",
    "在本章，你将学习如何创建自己的函数并运行它们。我们也将看到一个函数如何调用另一个函数。例如，我们将显示Monty Python歌曲的歌词。这些简单的示例展示了重要的特性：编写自己的函数是编程的基础。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4ea99c5",
   "metadata": {},
   "source": [
    "## 定义新函数\n",
    "\n",
    "**函数定义function definition**指定新函数的名字，以及函数调用时运行的语句序列。下面是一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d28f5c1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_lyrics():\n",
    "    print(\"I'm a lumberjack, and I'm okay.\")\n",
    "    print(\"I sleep all night and I work all day.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0174fc41",
   "metadata": {},
   "source": [
    "`def`是表示函数定义的关键字。上例定义的函数名是`print_lyrics`。所有合法的变量名都是合法的函数名。\n",
    "\n",
    "函数名后空的括号表示这个函数不接受任何参数。\n",
    "\n",
    "函数定义的第一行称为函数的**头部header**，剩余部分称为函数的**主体body**。函数头必须以冒号结尾，函数体必须缩进。通常缩进是4个空格。上例中函数体是两个print语句；总体而言，函数体可以包含任意数量任意类型的语句。\n",
    "\n",
    "定义函数将创建一个**函数对象function object**，我们可以像这样显示该对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2850a402",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.print_lyrics()>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print_lyrics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12bd0879",
   "metadata": {},
   "source": [
    "输出表明`print_lyrics`是不接受参数的函数。`__main__`是包含`print_lyrics`函数的模块名。\n",
    "\n",
    "译注：在最简单的情况下，`__main__`对应打开Python之后所处的环境。\n",
    "\n",
    "现在我们定义了一个函数，我们可以像调用内建函数一样调用它。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "9a048657",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I'm a lumberjack, and I'm okay.\n",
      "I sleep all night and I work all day.\n"
     ]
    }
   ],
   "source": [
    "print_lyrics()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f0fc45d",
   "metadata": {},
   "source": [
    "当运行函数时，将执行函数体中的语句，显示“The Lumberjack Song”中的前两行歌词。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d35193e",
   "metadata": {},
   "source": [
    "## 参数\n",
    "\n",
    "我们看到的有些函数是需要参数的；例如，当你调用`abs`函数，你需要传递一个数字作为参数；有些函数接受多个参数，例如`math.pow`接受两个参数，底数和指数。\n",
    "\n",
    "下面是接受一个参数的函数定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e5d00488",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_twice(string):\n",
    "    print(string)\n",
    "    print(string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1716e3dc",
   "metadata": {},
   "source": [
    "函数头括号中的变量称为**形式参数parameter**(简称形参)。当调用函数时，实际参数(argument，简称实参)的值被赋值给形参(parameter)。\n",
    "\n",
    "译注：**形式参数**是在函数定义时抽象的变量名，为表示函数体内部的逻辑而存在；**实际参数**是在函数调用时提供的变量，有实际的值。本章将明确区分两者，在后续章节不导致歧义的情况下统称参数。\n",
    "\n",
    "例如，我们可以像下面这样调用`print_twice`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a3ad5f46",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dennis Moore, \n",
      "Dennis Moore, \n"
     ]
    }
   ],
   "source": [
    "print_twice('Dennis Moore, ')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f02be6d2",
   "metadata": {},
   "source": [
    "这与将实参赋值给形参，然后调用函数体中的语句是相同的效果。\n",
    "\n",
    "译注:想象我们现在在`print_twice`的内部："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "042dfec1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dennis Moore, \n",
      "Dennis Moore, \n"
     ]
    }
   ],
   "source": [
    "string = 'Dennis Moore, '\n",
    "print(string)\n",
    "print(string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea8b8b6e",
   "metadata": {},
   "source": [
    "你也可以将变量作为实参，直接传递给函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "8f078ad0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dennis Moore, \n",
      "Dennis Moore, \n"
     ]
    }
   ],
   "source": [
    "line = 'Dennis Moore, '\n",
    "print_twice(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c1884ad",
   "metadata": {},
   "source": [
    "在上例中，`line`的值被赋值给形参`string`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3e5a790",
   "metadata": {},
   "source": [
    "## 调用函数\n",
    "\n",
    "一旦定义了函数，你可以在另一个函数中使用它。我们将编写函数,打印“The Spam Song”(<https://www.songfacts.com/lyrics/monty-python/the-spam-song>)的歌词。\n",
    "\n",
    "> Spam, Spam, Spam, Spam,  \n",
    "> Spam, Spam, Spam, Spam,  \n",
    "> Spam, Spam,  \n",
    "> (Lovely Spam, Wonderful Spam!)  \n",
    "> Spam, Spam,\n",
    "\n",
    "我们将使用下面的函数实现，它接受两个形参。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e86bb32c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def repeat(word, n):\n",
    "    print(word * n)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bdd4daa4",
   "metadata": {},
   "source": [
    "我们可以使用`repeat`函数打印歌词的第一行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ec117999",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "spam = 'Spam, '\n",
    "repeat(spam, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6f81e09",
   "metadata": {},
   "source": [
    "要显示前两行，我们可以定义一个新函数，使用到`repeat`函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3731ffd8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def first_two_lines():\n",
    "    repeat(spam, 4)\n",
    "    repeat(spam, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8058ffe4",
   "metadata": {},
   "source": [
    "然后调用它："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "6792e63b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "first_two_lines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07ca432a",
   "metadata": {},
   "source": [
    "要显示后3行，我们可以定义另一个函数，也用到`repeat`函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "2dcb020a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def last_three_lines():\n",
    "    repeat(spam, 2)\n",
    "    print('(Lovely Spam, Wonderful Spam!)')\n",
    "    repeat(spam, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9ff8c60e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "last_three_lines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6456a19",
   "metadata": {},
   "source": [
    "最后，我们可以将这些函数聚集到一个函数中，打印完整的歌词："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "78bf3a7b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_verse():\n",
    "    first_two_lines()\n",
    "    last_three_lines()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "ba5da431",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "print_verse()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d088fe68",
   "metadata": {},
   "source": [
    "当我们运行`print_verse`时，它会调用`first_two_lines`；`first_two_lines`会调用`repeat`；`repeat`会调用`print`。\n",
    "\n",
    "当然我们可以用更少的函数做相同的事，但这个例子的要点在于展示如何让若干函数一起工作。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3b16e3f",
   "metadata": {},
   "source": [
    "## 重复\n",
    "\n",
    "如果我们想要显示更多的歌词，我们可以使用`for`语句。下面是一个简单的例子。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "29b7eff3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "for i in range(2):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf320549",
   "metadata": {},
   "source": [
    "第一行是以冒号结尾的循环头部，剩余行是必须缩进的循环主体。\n",
    "\n",
    "头部以关键字`for`开始，然后是新的变量`i`，然后是新的关键字`in`。头部使用`range`函数创建包含`0`和`1`的序列，当我们进行计数时，我们通常从`0`开始。\n",
    "\n",
    "当执行`for`语句时，它将`range`中的第1个值传递给`i`，然后运行循环体中的`print`函数，将`0`显示出来；\n",
    "\n",
    "到达循环体的结尾时，它重新回到头部，因此这个语句称作**循环loop**。\n",
    "\n",
    "循环中的第2次该语句将`range`的下一个值传递给`i`，然后显示`1`。然后由于`1`是`range`的最后一个值，该循环结束。\n",
    "\n",
    "在下面，我们使用`for`循环语句打印两次歌词："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "038ad592",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Verse 0\n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n",
      "\n",
      "Verse 1\n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n",
      "\n"
     ]
    }
   ],
   "source": [
    "for i in range(2):\n",
    "    print(\"Verse\", i)\n",
    "    print_verse()\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88a46733",
   "metadata": {},
   "source": [
    "你可以将`for`循环语句放在函数中。例如，`print_n_verses`接受形参`n`，显示n次歌词。n必须是整数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "8887637a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_n_verses(n):\n",
    "    for i in range(n):\n",
    "        print_verse()\n",
    "        print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad8060fe",
   "metadata": {},
   "source": [
    "在上例中，我们在循环中不使用变量`i`，但是在循环头部中必须有一个变量名。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b320ec90",
   "metadata": {},
   "source": [
    "## 变量和形参是局部的\n",
    "\n",
    "当你在函数内部创建变量，它是**局部的local**，即这个变量只存在于函数内部。例如，下面的函数接受两个参数，拼接后打印两次。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "0db8408e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def cat_twice(part1, part2):\n",
    "    cat = part1 + part2\n",
    "    print_twice(cat)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a35a6d0",
   "metadata": {},
   "source": [
    "下面是一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "1c556e48",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Always look on the bright side of life.\n",
      "Always look on the bright side of life.\n"
     ]
    }
   ],
   "source": [
    "line1 = 'Always look on the '\n",
    "line2 = 'bright side of life.'\n",
    "cat_twice(line1, line2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ab4e008",
   "metadata": {},
   "source": [
    "当执行`cat_twice`时，将创建局部变量`cat`，该变量在函数结束时被销毁。如果我们尝试显示它，将产生`NameError`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "73f03eea",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'cat' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31mNameError\u001b[0m\u001b[0;31m:\u001b[0m name 'cat' is not defined\n"
     ]
    }
   ],
   "source": [
    "%%expect NameError\n",
    "\n",
    "print(cat)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ae36c29",
   "metadata": {},
   "source": [
    "在函数体外，`cat`变量未被定义。\n",
    "\n",
    "形参也是局部的。例如，在`cat_twice`函数定义之外，没有对应的`part1`或`part2`变量。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eabac8a6",
   "metadata": {},
   "source": [
    "## 栈图\n",
    "\n",
    "要跟踪每个变量在哪使用，有时绘制**栈图stack diagram**很有用。和状态图一样，栈图会显示每个变量的值，但栈图会显示每个变量所属的函数。\n",
    "\n",
    "每个函数显示为一个**帧frame**。帧是一个方框，外面有函数的名字，而函数的形参和局部变量在方框内部。\n",
    "\n",
    "上例的栈图如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "83df4e32",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from diagram import make_frame, Stack\n",
    "\n",
    "d1 = dict(line1=line1, line2=line2)\n",
    "frame1 = make_frame(d1, name='__main__', dy=-0.3, loc='left')\n",
    "\n",
    "d2 = dict(part1=line1, part2=line2, cat=line1+line2)\n",
    "frame2 = make_frame(d2, name='cat_twice', dy=-0.3, \n",
    "                    offsetx=0.03, loc='left')\n",
    "\n",
    "d3 = dict(string = line1+line2)\n",
    "frame3 = make_frame(d3, name='print_twice', \n",
    "                    offsetx=-0.28, offsety=-0.3, loc='left')\n",
    "\n",
    "d4 = {\"?\": line1+line2}\n",
    "frame4 = make_frame(d4, name='print', \n",
    "                    offsetx=-0.28, offsety=0, loc='left')\n",
    "\n",
    "stack = Stack([frame1, frame2, frame3, frame4], dy=-0.8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "bcd5e1df",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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yMggICCgXuPVJi4ujm7dumG32zl9+nSFZdHR0SxevBiA5cuXs3DhQn3Z888/j6+vL0899VS91nf9eyJ+uxrc6QLEr1dpaSmbNm3Cy8uL7t27A+Ds7MzcuXPx8PCgrKyMqKgoFixYwF//+tc7XO2tUVpaire3N8uXL7/hsWbNmsWLL77IvffeW+c+/fv3p3///je87rp6//33WbJkCd26daux3fXB/cMPP5CUlMS3336Lo6OcG4v6k6PmN8pkMhETE0NoaCheXl6sW7dOXzZ69GgCAgKwWq2Eh4dz8uRJ4OoZut1uZ+LEifTq1YvExERSUlKYN28edrudlStX8uijj+pnwU5OTnh7e1NQUHAnNhGAsrIy1q5dS3p6OhcuXKixbYsWLSq8/vDDD+nbty9du3atMDvw8PAgNjaWAQMGMHbs2Eozl8WLF+Pp6UlAQABvvPFGpVnUm2++Sc+ePenatSubN28GYMKECQCEhoZit9v1fX7NqVOnGDRoEH5+flitVv70pz8BkJCQQGRkpN7uH//4B127dqVfv358/vnnFcZYu3YtQUFB+Pv7069fv2pnjLm5ufTq1Qur1UpgYCA7d+4EIDIykqNHj/Lcc89VWGdVYmJimDJlCsXFxQwYMICLFy/i7+/P22+/DcC7775LYGAg/v7+hIWF8d1331U5zs/fE/HbJDOq3zAHBwe++OILjh49SlBQEFarlQceeIDZs2frXxBvv/02s2bN4q233gLgq6++Yu7cucTGxgJXw8vLy4uxY8dWGv/ChQusXLmSf/zjH7dvo37GycmJ9u3bk52dzb59++jatSvdu3encePGldqmp6dXeP3DDz/w+eefc/r0aXr27InFYsHHxweA7777jk2bNuHg4EBGRobe56uvvuLtt99m+/bttGzZkldeeaXCmGfOnMHLy4vXXnuNL774gldeeYU+ffowf/584uLi+OKLL2jSpEml2j744AMeeughNm7cqI/zc5999hmfffYZmZmZuLi4VLjMtnPnTj7++GM+//xznJ2d2bFjB6NHj2bHjh0Vxrhy5QojRozg3XffJSQkhKysLCIjI9m7dy/x8fF4eHgQHx/PH/7wh9p2PQDNmjXjo48+IiAggMzMTODqCcDhw4dJTU3FycmJtWvX8te//pUPPvigUv+fvyfit0mC6jfs6aefBuCRRx7BarWyY8cO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",
      "text/plain": [
       "<Figure size 380x291 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from diagram import diagram, adjust\n",
    "\n",
    "\n",
    "width, height, x, y = [3.8, 2.91, 1.15, 2.66]\n",
    "ax = diagram(width, height)\n",
    "bbox = stack.draw(ax, x, y)\n",
    "#adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "854fee12",
   "metadata": {},
   "source": [
    "帧按栈排列，标识哪个函数调用了哪个，并以此类推。从底部开始查看，`print`被`print_twice`调用，`print_twice`被`cat_twice`调用，`cat_twice`被`__main__`调用。`__main__`是最顶层帧的特殊名字。当你在函数外创建了变量名，它就属于`__main__`。\n",
    "\n",
    "译注：与数据结构中的“栈顶”，“栈底”不同，本节的表述是相反的。`__main__`实际是Python最“底层”的帧。以这种顺序表示主要是与下一节回溯信息的实现方式保持一致。\n",
    "\n",
    "在`print`帧中问号表示我们不知道形参的名字。如果你好奇的话，可以询问虚拟助手，“Python的print函数的形式参数是什么？”"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5690cfc0",
   "metadata": {},
   "source": [
    "## 回溯\n",
    "\n",
    "当在函数中出现运行时错误的时候，Python将显示函数的名字，调用这个函数的函数名，以此类推，直到栈顶。\n",
    "\n",
    "我会定义一个包含错误的`print_twice`版本作为例子。它尝试打印另一个函数的局部变量`cat`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "886519cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_twice(string):\n",
    "    print(cat)            # NameError\n",
    "    print(cat)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7c0713b",
   "metadata": {},
   "source": [
    "运行`cat_twice`，查看会发生什么："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "1fe8ee82",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception reporting mode: Verbose\n"
     ]
    }
   ],
   "source": [
    "# 这个单元格让Jupyter在出现运行时故障时提供更多调试信息。\n",
    "# 在进行练习前先运行本单元格。\n",
    "\n",
    "%xmode Verbose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "d9082f88",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'cat' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[27], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m cat_twice(line1, line2)\n        line1 \u001b[0;34m= 'Always look on the '\u001b[0m\u001b[0;34m\n        \u001b[0mline2 \u001b[0;34m= 'bright side of life.'\u001b[0m\n",
      "Cell \u001b[0;32mIn[20], line 3\u001b[0m, in \u001b[0;36mcat_twice\u001b[0;34m(part1='Always look on the ', part2='bright side of life.')\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcat_twice\u001b[39m(part1, part2):\n\u001b[1;32m      2\u001b[0m     cat \u001b[38;5;241m=\u001b[39m part1 \u001b[38;5;241m+\u001b[39m part2\n\u001b[0;32m----> 3\u001b[0m     print_twice(cat)\n        cat \u001b[0;34m= 'Always look on the bright side of life.'\u001b[0m\n",
      "Cell \u001b[0;32mIn[25], line 2\u001b[0m, in \u001b[0;36mprint_twice\u001b[0;34m(string='Always look on the bright side of life.')\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mprint_twice\u001b[39m(string):\n\u001b[0;32m----> 2\u001b[0m     \u001b[38;5;28mprint\u001b[39m(cat)            \u001b[38;5;66;03m# NameError\u001b[39;00m\n\u001b[1;32m      3\u001b[0m     \u001b[38;5;28mprint\u001b[39m(cat)\n",
      "\u001b[0;31mNameError\u001b[0m: name 'cat' is not defined"
     ]
    }
   ],
   "source": [
    "%%expect NameError\n",
    "\n",
    "cat_twice(line1, line2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f4defcf",
   "metadata": {},
   "source": [
    "错误信息中包含一个**回溯traceback**，显示错误产生时所在的函数，调用该函数的函数，以此类推。在这个例子中，它显示`cat_twice`调用了`print_twice`，而错误出现在`print_twice`中。\n",
    "\n",
    "回溯中的函数顺序与栈图的顺序一致。正在运行的函数在最底部。\n",
    "\n",
    "译注：与上面的栈图有些许不同，上面示例中的回溯没有将print函数的调用情况显示出来，这是因为print函数还没有加入栈，Python就发现了NameError,进行了回溯并终止了程序。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "374b4696",
   "metadata": {},
   "source": [
    "## 为什么使用函数？\n",
    "\n",
    "现在可能还不能体会到，麻烦地将程序分成若干个函数有什么价值。以下是一些原因：\n",
    "\n",
    "- 创建新函数让你能够给一组语句进行命名，让你的程序更加易于阅读和调试；\n",
    "- 通过消除重复代码，函数可以让程序更小。然后，如果你需要修改，你只需要修改一次；\n",
    "- 将长程序分为若干函数，可以让你一次调试一部分，然后将它们组装成一个整体；\n",
    "- 设计良好的函数通常对许多程序都有用。一旦你编写并调试好函数，你可以重复利用它。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6dd486e",
   "metadata": {},
   "source": [
    "## 调试\n",
    "\n",
    "调试可能是令人沮丧的，但也充满挑战，有时是有趣的。调试也是你可以学习的最重要的技能之一。\n",
    "\n",
    "调试在某些方面像是侦探工作。你获得了一些线索，你必须从你看到的结果，推断发生了什么事。\n",
    "\n",
    "调试也像是实验科学，一旦你觉得哪里出错了，你可以修改程序并再试一遍。如果你的假设正确，你可以预测修改的结果，从而更接近正确的程序。如果假设错误，你必须重新进行假设。\n",
    "\n",
    "对于有些人，编程和调试是同一件事，也即编程是不断调试直到满足要求的过程。你应该从有效的程序开始，不断地修改并且调试。\n",
    "\n",
    "如果你发现自己花了许多时间进行调试，通常说明你在测试之前写了太多代码。如果你及时测试，你的编程速度可能更快。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4e95e63",
   "metadata": {},
   "source": [
    "## 术语表\n",
    "\n",
    "- **函数定义function definition**：创建函数的语句；\n",
    "- 函数**头部header**：函数定义的第一行；\n",
    "- 函数**主体body**：函数定义中的语句序列；\n",
    "- **函数对象function object**：由函数定义创建的值。函数的名字是一个变量，指向函数对象；\n",
    "- **形式参数parameter**：函数中使用的变量名，用于接受实际参数的值；\n",
    "- **循环loop**：执行若干语句的语句，通常是重复执行；\n",
    "- **局部变量local variable**：在函数内部定义的变量，只能在函数内部被访问；\n",
    "- **栈图stack diagram**：函数变量与指向的值的栈的图形化表示；\n",
    "- **栈帧frame**：栈图中表示一个函数调用的方框。包含该函数的局部变量和形参；\n",
    "- **回溯traceback**：一系列执行中的函数，当错误发生时会被打印。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eca485f2",
   "metadata": {},
   "source": [
    "## 练习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "3f77b428",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception reporting mode: Verbose\n"
     ]
    }
   ],
   "source": [
    "# 这个单元格让Jupyter在出现运行时故障时提供更多调试信息。\n",
    "# 在进行练习前先运行本单元格。\n",
    "\n",
    "%xmode Verbose"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82951027",
   "metadata": {},
   "source": [
    "### 询问虚拟助手\n",
    "\n",
    "习惯上函数或者`for`循环中的语句缩进为4个空格。但不是所有人都同意。如果好奇关于这个争论的历史，询问虚拟助手“告诉我更多Python中关于空格和制表符的历史”。\n",
    "\n",
    "虚拟助手善于编写小的函数。\n",
    "\n",
    "1. 让虚拟助手“编写一个函数，函数名为repeat，函数接受一个字符串和一个整数，将字符串打印指定次数”。\n",
    "2. 如果结果中包含`for`循环，你可以询问：“你能在这个函数中不使用for循环吗？”\n",
    "3. 选择本章的其他函数，让虚拟助手编写。挑战在于精确地描述函数，得到你想要的功能。使用你目前学到的编程词汇。\n",
    "\n",
    "虚拟助手也善于对函数进行调试。\n",
    "\n",
    "1. 询问虚拟助手以下版本的`print_twice`错误在哪。\n",
    "\n",
    "```py\n",
    "def print_twice(string):\n",
    "    print(cat)\n",
    "    print(cat)\n",
    "```\n",
    "\n",
    "如果下面的练习中有些卡住了你，尝试询问虚拟助手。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7157b09",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "编写函数`print_right`，接受字符串形参`text`，打印该字符串，用空格填充左边，从而让`text`中的最后一个字母出现在一行的第40列。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "428fbee5",
   "metadata": {},
   "source": [
    "提示：使用`len`函数，字符串的拼接运算符`+`，以及字符串重复运算符`*`。\n",
    "\n",
    "以下是一些示例。\n",
    "\n",
    "```py\n",
    "print_right(\"Monty\")\n",
    "print_right(\"Python's\")\n",
    "print_right(\"Flying Circus\")\n",
    "```\n",
    "\n",
    "输出：\n",
    "\n",
    "```txt\n",
    "                                   Monty\n",
    "                                Python's\n",
    "                           Flying Circus\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b47467fa",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "编写函数`triangle`，接受一个字符和一个整数，绘制指定高度的金字塔，每行由重复的字符组成，且每行的字符数量增加1。以下是一个`5`层的`L`金字塔。\n",
    "\n",
    "```py\n",
    "triangle('L', 5)\n",
    "```\n",
    "\n",
    "输出：\n",
    "\n",
    "```txt\n",
    "L\n",
    "LL\n",
    "LLL\n",
    "LLLL\n",
    "LLLLL\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a28f635",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "编写函数`rectangle`，接受一个字符和两个整数，用指定的字符绘制指定宽度和高度的矩形。以下是一个宽度`width`为`5`,高度`height`为`4`的由字符`H`绘制的示例。\n",
    "\n",
    "```py\n",
    "rectangle('H', 5, 4)\n",
    "```\n",
    "\n",
    "输出：\n",
    "\n",
    "```txt\n",
    "HHHHH\n",
    "H   H\n",
    "H   H\n",
    "HHHHH\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44a5de6f",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "歌曲“99 Bottles of Beer”的第一段歌词为：\n",
    "\n",
    "> 99 bottles of beer on the wall  \n",
    "> 99 bottles of beer  \n",
    "> Take one down, pass it around  \n",
    "> 98 bottles of beer on the wall  \n",
    "\n",
    "第二段歌词与第一段基本相同，只是前两行的99变为98,最后一行的98变成97。这个歌会一直进行，直到最后只剩下0瓶啤酒。\n",
    "\n",
    "编写函数`bottle_verse`，接受一个数字作为形参，显示从指定数量啤酒开始的那段歌词。\n",
    "\n",
    "注意：考虑定义可以打印第1,2或第4行歌词的函数，然后在`bottle_verse`中调用这个（些）函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee0076dd",
   "metadata": {
    "tags": []
   },
   "source": [
    "以下是一个示例：\n",
    "\n",
    "```py\n",
    "bottle_verse(42)\n",
    "```\n",
    "\n",
    "输出：\n",
    "\n",
    "```txt\n",
    "42 bottles of beer on the wall  \n",
    "42 bottles of beer  \n",
    "Take one down, pass it around  \n",
    "41 bottles of beer on the wall  \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42c237c6",
   "metadata": {
    "tags": []
   },
   "source": [
    "如果你想要打印完整歌词，你可以使用`for`循环，从`99`倒数到`1`。你不需要完全理解下面的例子，在后续章节会进一步学习`for`循环和`range`函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59352c19",
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in range(99, 0, -1):\n",
    "    bottle_verse(n)\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7f4edf8",
   "metadata": {
    "tags": []
   },
   "source": [
    "[Think Python: 3rd Edition](https://allendowney.github.io/ThinkPython/index.html)\n",
    "\n",
    "Copyright 2024 [Allen B. Downey](https://allendowney.com)\n",
    "\n",
    "Code license: [MIT License](https://mit-license.org/)\n",
    "\n",
    "Text license: [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
